﻿using System;
using System.IO.Ports;
using System.Collections;
using System.Collections.Generic;
using System.Threading;

namespace CabCtlLib
{
    /// <summary>
    /// CabCtl 的摘要说明
    /// </summary>
    public class CabCtl
    {
        /// <summary>锁状态检测开锁状态以外字符串</summary>
        const string LOCK_EXCEPT = "FF 00 FF 00 FF 00";
        /// <summary>快递柜状态：锁闭</summary>
        const int CAB_STATUS_LOCK = 1;
        /// <summary>快递柜状态：开启</summary>
        const int CAB_STATUS_UNLOCK = 0;
        /// <summary>快递柜状态：未知</summary>
        const int CAB_STATUS_UNKNOWN = -1;

        /// <summary>
        /// 状态检测结果接收事件委托
        /// </summary>
        /// <param name="cabLockStatus">快递柜状态</param>
        public delegate void ReceivedHandler(string cabLockStatus);
        /// <summary>状态检测结果接收事件</summary>
        public static event ReceivedHandler Received;

        /// <summary>串口对象</summary>
        private static SerialPort sp;
        /// <summary>串口对象词典</summary>
        private static Dictionary<string, SerialPort> spDic = new Dictionary<string, SerialPort>();

        private static string portName;
        private static string cmdOpen;
        private static string cmdCheck;

        /// <summary>
        /// 执行打开快递柜命令
        /// </summary>
        /// <param name="portName">串口名称</param>
        /// <param name="cmdOpen">开柜命令</param>
        /// <returns>True:执行成功，False:执行失败</returns>
        public static bool OpenCab(string portName, string cmdOpen)
        {
            Log.Write("#####OpenCab#####");
            Log.Write("portName:" + portName);
            Log.Write("cmdOpen:" + cmdOpen);
            Log.Write("cmdCheck:" + cmdCheck);
            CabCtl.portName = portName;
            CabCtl.cmdOpen = cmdOpen;
            return OpenSerialPort() && SendCmdOpen(); 
        }

        /// <summary>
        /// 执行检测快递柜状态命令
        /// </summary>
        /// <param name="portName">串口名称</param>
        /// <param name="cmdCheck">状态检测命令</param>
        /// <returns>True:执行成功，False:执行失败</returns>
        public static bool CheckCab(string portName, string cmdCheck)
        {
            Log.Write("#####CheckCab#####");
            Log.Write("portName:" + portName);
            Log.Write("cmdCheck:" + cmdCheck);
            CabCtl.portName = portName;
            CabCtl.cmdCheck = cmdCheck;
            return OpenSerialPort() && SendCmdCheck();
        }

        /// <summary>
        /// 打开串口通信
        /// </summary>
        /// <param name="portName">串口名称</param>
        /// <returns>True:执行成功，False:执行失败</returns>
        private static bool OpenSerialPort()
        {
            Log.Write("#####OpenSerialPort#####");
            try
            {
                if (!spDic.ContainsKey(portName))
                {
                    SerialPort temp = new SerialPort(portName);
                    temp.Open();
                    spDic.Add(portName, temp);
                }

                sp = spDic[portName];
                return true;
            }
            catch(Exception e)
            {
                Log.Write("function:OpenSerialPort");
                Log.Write("Exception:" + e.Message);
                return false;
            }
        }

        /// <summary>
        /// 发送开柜命令
        /// </summary>
        /// <param name="cmdOpen">开柜命令</param>
        /// <returns>True:发送成功，False:发送失败</returns>
        private static bool SendCmdOpen()
        {
            Log.Write("#####SendCmdOpen#####");
            try
            {
                byte[] bytesOpen = GetCmdBytes(cmdOpen);
                if (bytesOpen == null)
                {
                    return false;
                }

                sp.DiscardInBuffer();
                sp.DiscardOutBuffer();
                sp.Write(bytesOpen, 0, 7);
                Thread.Sleep(100);

                return true;
            }
            catch (Exception e)
            {
                Log.Write("function:SendCmdOpen");
                Log.Write("Exception:" + e.Message);
                return false;
            }
        }

        /// <summary>
        /// 发送状态检测命令
        /// </summary>
        /// <param name="cmdCheck">状态检测命令</param>
        /// <returns>True:发送成功，False:发送失败</returns>
        private static bool SendCmdCheck()
        {
            Log.Write("#####SendCmdCheck#####");
            try
            {  
                byte[] bytesCheck = GetCmdBytes(cmdCheck);
                if (bytesCheck == null)
                {
                    return false;
                }

                Thread.Sleep(100);
                sp.DiscardInBuffer();
                sp.DiscardOutBuffer();
                sp.DataReceived += CheckDataReceived;
                sp.Write(bytesCheck, 0, 7);
                Thread.Sleep(100);

                return true;
            }
            catch (Exception e)
            {
                Log.Write("function:SendCmdCheck");
                Log.Write("Exception:" + e.Message);
                return false;
            }
        }

        /// <summary>
        /// 接受检测状态命令的串口响应消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void CheckDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            Log.Write("#####CheckDataReceived#####");
            byte[] bytes = new byte[6];
            string cabStatus = string.Empty;
            sp.Read(bytes, 0, 6);
            cabStatus = GetHexStr(bytes);
            Log.Write("cabStatus:" + cabStatus);
            Received(cabStatus);

            sp.DataReceived -= CheckDataReceived;
        }

        /// <summary>
        /// 将byte数组转换为十六进制字符串（带有空格）
        /// </summary>
        /// <param name="bytes">byte数组</param>
        /// <returns>十六进制字符串（带有空格</returns>
        private static string GetHexStr(byte[] bytes)
        {
            string hexStr = string.Empty;
            for (int i = 0; i < bytes.Length; i++)
            {
                hexStr += Convert.ToString(bytes[i], 16).PadLeft(2, '0').ToUpper() + " ";
            }
            return hexStr.Trim();
        }

        /// <summary>
        /// 将cmd转换为字符byte数组（用于发送）
        /// </summary>
        /// <param name="cmd">cmd（十六进制，带有空格）</param>
        /// <returns>byte数组（用于发送）</returns>
        private static byte[] GetCmdBytes(string cmd)
        {
            if (string.IsNullOrEmpty(cmd))
            {
                return null;
            }

            string content = cmd.Replace(" ", "").Trim();

            if (content.Length != 14)
            {
                return null;
            }

            byte[] bytes = new byte[7];
            bytes[0] = (byte)Convert.ToInt32(content.Substring(0, 2), 16);
            bytes[1] = (byte)Convert.ToInt32(content.Substring(2, 2), 16);
            bytes[2] = (byte)Convert.ToInt32(content.Substring(4, 2), 16);
            bytes[3] = (byte)Convert.ToInt32(content.Substring(6, 2), 16);
            bytes[4] = (byte)Convert.ToInt32(content.Substring(8, 2), 16);
            bytes[5] = (byte)Convert.ToInt32(content.Substring(10, 2), 16);
            bytes[6] = (byte)Convert.ToInt32(content.Substring(12, 2), 16);
            return bytes;
        }
    }
}
